TFM API

1) Estadística descriptiva

Vemos que son 3658 registros sobre los que se evalúan 19 características.

1. Establecemos el índice para el conjunto de datos

Creemos conveniente convertir alguna de las columnas en el índice del dataset, si es posible. A priori, la columna "propertyCode" parece que puede ser el índice del conjunto de datos, pues debe ser un código / identificador único.

Sin embargo, vemos que hay varios registros para un mismo código de propiedad (puede tratarse de un anuncio publicado por varias inmobiliarias a la vez). Por tanto, como la columna "propertyCode" no tiene entradas únicas (no corresponde con el total de registros del dataframe), no podemos definirlo como el índice del dataset.

2. Estudiamos los elementos duplicados

Vemos que parece que hay 751 filas con el propertyCode duplicado. Si miramos algunos ejemplos, vemos que las únicas variaciones que encontramos son en las medidas de latitud y longitud, datos que son sensibles a pequeñas variaciones.

Intentaríamos conseguir más información sobre si es posible que un mismo inmueble pueda estar publicado por dos o más agencias diferentes, lo que también explicaría estas pequeñas variaciones en las coordenadas geográficas, según el dispositivo desde donde se extraigan.

También es posible que, debido a la forma en la que se han hecho las peticiones a la API (indicando un punto central y un barrio), se hayan solapado las circunferencias y se hayan devuelto varios registros por partida doble.

Bajo esta hipótesis, consideramos eliminar los registros con los propertyCode duplicados, quedándonos con cualquiera de los registros, suponiendo que ambas coordenadas son igualmente válidas.

Ahora ya hemos conseguido que el número de valores únicos de la columna "propertyCode" corresponda con el total de registros del dataframe, por lo que podemos definirlo como el índice del dataset.

3. Tipo de datos

Indicamos qué recoge cada variable:

Infiriendo qué recoge cada uno de los datos que hemos descargado a partir de la web y de la observación del dataset, creemos que sería necesario implementar varias modificaciones para transformar las variables al tipo más adecuado. Sin embargo, no lo vamos a realizar ahora, sino que vamos a seguir con los siguientes puntos y lo tendremos en cuenta si es necesario transformarlo más adelante.

# La variable del código identificador de la propiedad está declarada como un entero, pero realmente es de tipo String, a pesar de que sean números. Puesto que no vamos a realizar operaciones aritméticas con este dato, no lo consideramos un entero, sino un literal, por lo que hacemos una nueva conversión para esta columna. 

df_api["propertyCode"] = df_api["propertyCode"].astype("object")

# Hay variables booleanas que no están definidas como tal:
df_api["exterior"] = df_api["exterior"].astype("bool")
df_api["hasLift"] = df_api["hasLift"].astype("bool")
df_api["parkingSpace"] = df_api["parkingSpace"].astype("bool")

4. Exploración y tratamiento de los datos faltantes

Si analizamos los NA's, vemos que 6 de las 19 variables que estamos teniendo en cuenta, tienen datos faltantes. En término porcentuales, apenas supone el 5% de los datos totales.

A continuación, realizamos un estudio de estas seis variables para identificar la razón por la que hay datos faltantes e intentar encontrar la manera de rellenarlos. (hipótesis 3) Implementaremos algunas técnicas que pueden ayudarnos con los valores perdidos, pero tenemos en cuenta que probablemente también acabarán eliminando alguna información útil o añadiendo algo de ruido a nuestros datos.

CASO 1: Los valores faltantes corresponden a una categoría de la variable

CASO 2: Los valores faltantes corresponden a datos no registrados por error

Comprobamos que se han implementado correctamente los datos y ya no tenemos ningún valor faltante en el dataset.

5. Exploración y tratamiento de datos atípicos

En este punto, vamos a revisar las características de cada columna, centrándonos en los valores que toma cada variable y concretamente, en si existe algún valor atípico (outlier) dentro de nuestros datos.

Estos pueden tener diferentes significados: tratarse de un error en el registro de los datos, escaparse simplemente del rango donde se concentran la mayoría de valores pero ser un dato válido o puede que sea un dato que queremos detectar y que sea el objetivo del estudio. En cada caso, definiremos la estrategia que consideras más adecuada para tratarlos.

Esto nos ha servido para observar que hay barrios mal codificados, por lo que aprovechamos para corregir estos errores tipográficos y así poder unificarlos.

6. Gráficos

Atendiendo a la estadística descriptiva, vemos que el precio medio de las propiedades supera los 650.000€, alcanzando el inmueble más caro un precio de casi 9M, mientras que el más barato se vende por 50.000€.

Los datos recogidos indican que el tamaño medio es de casi 135 m2. Por otra parte, cabe destacar que las propiedades en Madrid suelen tener 3 habitaciones y 2 baños, en mediana.

Por otra parte, el perfil del inmueble prototipo que encontramos es un piso en buen estado situado en el primer piso de un edificio ubicado en el distrito de Carabanchel, concretamente, en el barrio de Vista Alegre.

Es un piso exterior y no es de nueva construcción. Cuenta con ascensor, pero no con espacio de aparcamiento.

A continuación, decidimos realizar varios gráficos que nos representen a simple vista, los datos que hemos ido analizando.

7. Discretización de variables

Para algunos algoritmos de Machine Learning, será necesario tener las variables categóricas en formato numérico. Para ello, en este punto, vamos a utilizar diferentes técnicas para la discretización de las columnas no numéricas, para poder ser tratadas por estos algoritmos. Para ello, habiendo visto cómo se distribuyen los valores de cada una de las variables, las podemos discretizar de diferente forma.

En nuestro caso, las variables categóricas son:

Variables como adress o description no tienen poder predictivo, por lo que no son de interés para nuestro modelo y decidimos no tratarlas.

#### Variable "district"

# Para convertirlo a numérico, podemos modelarlo asignando a cada valor actual, un número. 
# Podríamos aplicar este mapeo, pero decidimos convertirlas mediante One-hot encoding (apartado a continuación)

# Vemos cómo se distribuyen los valores de la variable
categorias = (df_api_discretizado[["district"]].value_counts())

# Empezamos definiendo una lista con las categorías actuales
categorias_actuales = [cat[0] for cat in categorias.index]

# Creamos las nuevas categorías, que van a corresponder con las respectivas posiciones
nuevas_categorias = [elem for elem in range(0, len(categorias_actuales))]

# Creamos el diccionario
my_mapping = dict()

for col_name, new_name in zip(categorias_actuales, nuevas_categorias):
    my_mapping[col_name] = new_name 

# Vemos cuál es la asociación de valores que se ha hecho (usaremos la misma para el df de Kaggle)
print(my_mapping)

# Por último, sustituimos los valores de la columna por nuestro mapeo
df_api_discretizado["district"] = df_api_discretizado["district"].replace(my_mapping)

Para la variable "district" podríamos aplicar un mapeo, pero decidimos aplicar One-hot encoding también, ya que no son excesivamente muchas categorías como sí ocurre con la variable "neighborhood".

Por último, mostramos cómo ha quedado el dataframe, viendo que las columnas dummies se han añadido al final:

Unificamos los formatos de df_kaggle y df_API

Dado que train (df_Kaggle) y test (df_API) deben tener el mismo esqueleto, tenemos que realizar una serie de operaciones.

Este dataset con datos extraídos de la API, va a ser el dataset de test.

Ya estamos en disposición de entrenar modelos de ML para predecir los precios de los inmuebles.